package com.sea.base.widget

import android.content.Context
import android.util.AttributeSet
import android.view.ViewGroup
import android.view.WindowInsets
import android.widget.FrameLayout
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.forEach
import com.sea.base.ext.global.throwIfDebug
import com.sea.base.ext.view.setPaddingOtherDefault
import com.sea.base.utils.StatusNavigationBarUtil

/**
 * 当绘制全屏时，会顶出状态栏、导航栏以及出现输入法不适应的问题，都在这里处理
 */
class FitsSystemWindowsFrameLayout @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) :
    FrameLayout(context, attrs, defStyleAttr) {

    companion object {
        const val IME_TYPE_NOTHING = 0

        /**
         * 压缩模式
         * 压缩后EditText弹起后底部至少留的距离见[adjustResizeEditTextMinBottomMargin]
         */
        const val IME_TYPE_ADJUST_RESIZE = 1

        /**
         * 平移模式
         */
        const val IME_TYPE_ADJUST_PAN = 2
    }

    private var showStatusBarHeight = 0
    private var showNavigationBarHeight = 0
    private var showImeHeight = 0

    /**
     * PaddingTop为StatusBar的大小
     */
    var paddingStatusBar = true

    /**
     * PaddingBottom为NavigationBar的大小
     */
    var paddingNavigationBar = true

    /**
     * 导航栏原本是半透明的，默认将导航栏设置为全透明
     */
    var transparentNavigationBar = true
        set(value) {
            field = value
            if (value) {
                //rootView会给导航栏设置半透明效果，这里拦截不让rootView处理就行了，只能做到大部分不是所有手机都有效
                rootView?.setOnApplyWindowInsetsListener { _, insets -> insets }
            } else {
                rootView?.setOnApplyWindowInsetsListener(null)
            }
        }

    /**
     * 软键盘属性，和“android:windowSoftInputMode”一样，见[IME_TYPE_ADJUST_RESIZE]
     */
    var imeType = IME_TYPE_NOTHING

    /**
     * 使用[imeType]时可能出现：EditText被顶出去、底部留白过长等问题，这里增加一个修正值
     * [imeType]3个属性均有效，根据相对位置继续平移距离，>0表示继续向下平移指定距离，=0表示默认距离，<0表示继续向上平移指定距离
     */
    var imeTypeOffset = 0

    /**
     * 压缩模式：压缩后EditText弹起后底部至少要留的距离，如果想展示到底部可以写一个很大值
     * 注意：实现者是[MyNestedScrollView]，所以你需添加[MyNestedScrollView]
     */
    var adjustResizeEditTextMinBottomMargin: Int
        get() {
            return findMyNestedScrollView(this, 1)?.adjustResizeEditTextMinBottomMargin ?: 0
        }
        set(value) {
            findMyNestedScrollView(this, 1)?.adjustResizeEditTextMinBottomMargin = value
        }

    override fun onApplyWindowInsets(insets: WindowInsets): WindowInsets {
        //WindowInsetsCompat只是统一了api，在低api并不能识别软键盘和导航栏，所以有下面的判断和逻辑
        val insetsIme = WindowInsetsCompat.toWindowInsetsCompat(insets).getInsets(WindowInsetsCompat.Type.ime() or WindowInsetsCompat.Type.systemBars())
        showStatusBarHeight = insetsIme.top
        val bottom = insetsIme.bottom
        if (bottom < StatusNavigationBarUtil.navigationBarHeight * 2) {
            //因为ime远大于导航栏，所以2倍以内默认均为导航栏
            showNavigationBarHeight = bottom
            showImeHeight = 0
        } else {
            //2倍以外默认为ime
            showImeHeight = bottom
        }
        refreshState()
        return insets
    }

    private fun refreshState() {
        val top = if (paddingStatusBar) showStatusBarHeight else 0
        var ty = 0f
        var bottom = 0
        when {
            showImeHeight > 0 && imeType == IME_TYPE_ADJUST_RESIZE -> {
                bottom = showImeHeight - imeTypeOffset
            }

            showImeHeight > 0 && imeType == IME_TYPE_NOTHING -> {
                ty = imeTypeOffset.toFloat()
            }

            showImeHeight > 0 && imeType == IME_TYPE_ADJUST_PAN -> {
                ty = (-showImeHeight + imeTypeOffset).toFloat()
            }

            paddingNavigationBar -> {
                bottom = showNavigationBarHeight
            }
        }
        setPaddingOtherDefault(top = top, bottom = bottom)
        translationY = ty
    }

    override fun onAttachedToWindow() {
        super.onAttachedToWindow()
        //自刷新导航栏透明度
        transparentNavigationBar = transparentNavigationBar
    }

    /**
     * @param deep 遍历深度，超过8级没必要继续递归了
     */
    private fun findMyNestedScrollView(view: ViewGroup, deep: Int): MyNestedScrollView? {
        if (deep > 8) return null
        when (view) {
            is MyNestedScrollView -> return view
            else -> {
                view.forEach { child ->
                    if (child is ViewGroup) {
                        findMyNestedScrollView(child, deep + 1)?.let { return it }
                    }
                }
            }
        }
        "尚未添加MyNestedScrollView或view层级嵌套太深无法找到".throwIfDebug { deep == 1 }
        return null
    }
}